/*
 * Copyright (C) 2010-2011 Comcast Cable.  All Rights Reserved.
 */
package com.hercules.android.receiver.handlers.events.listener;

import com.hercules.android.receiver.AndroidReceiver;
import com.hercules.android.receiver.ApplicationData;
import com.hercules.android.receiver.handlers.events.EventRaiser;
import com.hercules.android.receiver.handlers.events.EventsUtil;
import com.hercules.android.receiver.model.events.XREEvent;
import com.hercules.android.receiver.model.objects.XREObject;

/**
 * <p>
 * This is the base class for all Android listeners of this component. It defines some common properties that subclasses
 * need, as well as a setNextEventIndex() method that thread-safely sets the event index for the next event and update
 * the event index on the receiver.
 * </p>
 * <p>
 * <strong>Thread safety: </strong> This class is thread-safe because it's immutable, the EventRaiser it calls is
 * thread-safe, and its setNextEventIndex() has a synchronization block on ApplicationData. The concrete subclasses of
 * this class must be thread-safe
 * </p>
 *
 * @author mekanizumu, jaindsonvs
 * @version 1.0
 */
public abstract class BaseListener {
    /**
     * <p>
     * The receiver that will be passed to Android listeners of this component.
     * </p>
     * <p>
     * Initialization and Mutability: It's initialized within constructor, won't change afterwards.
     * </p>
     * <p>
     * Usage: It is used in getReceiver(), BaseListener() (for initialization), setNextEventIndex().
     * </p>
     */
    private final AndroidReceiver receiver;

    /**
     * <p>
     * The source of the event.
     * </p>
     * <p>
     * Initialization and Mutability: It's initialized within constructor, won't change afterwards.
     * </p>
     * <p>
     * Usage: It is used in BaseListener() (for initialization), getSource().
     * </p>
     */
    private final XREObject source;

    /**
     * <p>
     * The event type that the listener will react to.
     * </p>
     * <p>
     * Initialization and Mutability: It's initialized within constructor, won't change afterwards.
     * </p>
     * <p>
     * Usage: It is used in BaseListener() (for initialization), getEventType().
     * </p>
     */
    private final String eventType;

    /**
     * <p>
     * The EventRaiser used to raise a XRE event.
     * </p>
     * <p>
     * Initialization and Mutability: It's initialized within constructor, won't change afterwards.
     * </p>
     * <p>
     * Usage: It is used in BaseListener() (for initialization), getEventRaiser().
     * </p>
     */
    private final EventRaiser eventRaiser;

    /**
     * <p>
     * Create an instance of the class.
     * </p>
     *
     * @param eventRaiser the EventRaiser used to raise a XRE event.
     * @param source the source of the event.
     * @param receiver the receiver that will be passed to Android listeners of this component.
     * @param eventType the event type that the listener will react to.
     * @throws IllegalArgumentException if receiver doesn't conform to the following legal value specification: It
     * cannot be null. Or source doesn't conform to the following legal value specification: It cannot be null. Or
     * eventType doesn't conform to the following legal value specification: It cannot be null or empty. Or eventRaiser
     * doesn't conform to the following legal value specification: It cannot be null.
     */
    protected BaseListener(AndroidReceiver receiver, XREObject source, String eventType, EventRaiser eventRaiser) {
        EventsUtil.checkArgumentNull(receiver, "receiver");
        EventsUtil.checkArgumentNull(source, "source");
        EventsUtil.checkArgumentNull(eventType, "eventType");
        EventsUtil.checkArgumentEmpty(eventType, "eventType");
        EventsUtil.checkArgumentNull(eventRaiser, "eventRaiser");

        this.receiver = receiver;
        this.source = source;
        this.eventType = eventType;
        this.eventRaiser = eventRaiser;
    }

    /**
     * <p>
     * Set the index of the next event and update the event index of the receiver.
     * </p>
     *
     * @param event the event for which the index is set.
     * @throws IllegalArgumentException if event is null;
     */
    protected void setNextEventIndex(XREEvent event) {

        EventsUtil.checkArgumentNull(event, "event");

        ApplicationData appData = this.receiver.getApplicationData();

        synchronized (appData) {
            // Update the current event index in application data and use this value to set the index of the event.
            appData.setCurrentEventIndex(appData.getCurrentEventIndex() + 1);
            event.setEventIndex(appData.getCurrentEventIndex());
        }
    }

    /**
     * <p>
     * Getter for the event type that the listener will react to.
     * </p>
     *
     * @return the event type that the listener will react to.
     */
    protected String getEventType() {
        return this.eventType;
    }

    /**
     * <p>
     * Getter for the EventRaiser used to raise a XRE event.
     * </p>
     *
     * @return the EventRaiser used to raise a XRE event.
     */
    protected EventRaiser getEventRaiser() {
        return this.eventRaiser;
    }

    /**
     * <p>
     * Getter for the receiver that will be passed to Android listeners of this component.
     * </p>
     *
     * @return the receiver that will be passed to Android listeners of this component.
     */
    protected AndroidReceiver getReceiver() {
        return this.receiver;
    }

    /**
     * <p>
     * Getter for the source of the event.
     * </p>
     *
     * @return the source of the event.
     */
    protected XREObject getSource() {
        return this.source;
    }
}
